package edu.nwpu.zya.coreops.modules.resource.service.impl;

import com.alibaba.fastjson.JSONObject;
import edu.nwpu.zya.coreops.common.utils.Constant;
import edu.nwpu.zya.coreops.modules.alert.entity.RuleEcsRelationEntity;
import edu.nwpu.zya.coreops.modules.alert.service.DescriptionService;
import edu.nwpu.zya.coreops.modules.alert.service.RuleEcsRelationService;
import edu.nwpu.zya.coreops.modules.alert.service.RuleService;
import edu.nwpu.zya.coreops.modules.job.entity.JobEcsRelationEntity;
import edu.nwpu.zya.coreops.modules.job.entity.ScheduleJobEntity;
import edu.nwpu.zya.coreops.modules.job.service.JobEcsRelationService;
import edu.nwpu.zya.coreops.modules.job.service.ScheduleJobService;
import edu.nwpu.zya.coreops.modules.monitor.entity.MetricEntity;
import edu.nwpu.zya.coreops.modules.monitor.service.MetricService;
import edu.nwpu.zya.coreops.modules.resource.entity.EcsMetricRelationEntity;
import edu.nwpu.zya.coreops.modules.resource.service.EcsMetricRelationService;
import edu.nwpu.zya.coreops.modules.resource.vo.MetricVo;
import edu.nwpu.zya.coreops.modules.resource.vo.EcsVo;
import edu.nwpu.zya.coreops.modules.sys.entity.SysUserEntity;
import edu.nwpu.zya.coreops.modules.sys.service.SysUserService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import edu.nwpu.zya.coreops.common.utils.PageUtils;
import edu.nwpu.zya.coreops.common.utils.Query;

import edu.nwpu.zya.coreops.modules.resource.dao.EcsDao;
import edu.nwpu.zya.coreops.modules.resource.entity.EcsEntity;
import edu.nwpu.zya.coreops.modules.resource.service.EcsService;
import org.springframework.transaction.annotation.Transactional;


@Service("ecsService")
public class EcsServiceImpl extends ServiceImpl<EcsDao, EcsEntity> implements EcsService {
    @Autowired
    private MetricService metricService;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private EcsMetricRelationService ecsMetricRelationService;

    @Autowired
    private RuleEcsRelationService ruleEcsRelationService;

    @Autowired
    private RuleService ruleService;

    @Autowired
    private DescriptionService descriptionService;

    @Autowired
    private ScheduleJobService scheduleJobService;

    @Autowired
    private JobEcsRelationService jobEcsRelationService;

    /**
     * 返回EcsVo的分页
     * @param params
     * @return
     */
    @Override
    public PageUtils queryEcsVoPage(Map<String, Object> params) {
        String type = (String) params.get("type");
        String key = (String) params.get("key");

        QueryWrapper<EcsEntity> queryWrapper = new QueryWrapper<EcsEntity>();

        if (!StringUtils.isEmpty(type) && !StringUtils.isEmpty(key)) {
            if ("ecsId".equalsIgnoreCase(type)) {
                queryWrapper.eq("ecs_id", key);
            } else if ("name".equalsIgnoreCase(type)) {
                queryWrapper.like("name", key);
            } else if ("area".equalsIgnoreCase(type)) {
                queryWrapper.like("area", key);
            }
        }

        // 根据用户id查ECS
        Long userId = (Long) params.get("userId");
        if (!(userId.intValue() ==Constant.SUPER_ADMIN)) {
            queryWrapper.eq("user_id", userId);
        }
        IPage<EcsEntity> page = this.page(
                new Query<EcsEntity>().getPage(params),
                queryWrapper
        );
        PageUtils pageUtils = new PageUtils(page);
        if (page.getSize() > 0) {
            List<EcsVo> ecsVoList = page.getRecords().stream().map(ecsEntity -> {
                EcsVo ecsVo = new EcsVo();
                BeanUtils.copyProperties(ecsEntity, ecsVo);
                SysUserEntity sysUserEntity = sysUserService.getById(ecsEntity.getUserId());
                ecsVo.setUsername(sysUserEntity.getUsername());
                return ecsVo;
            }).collect(Collectors.toList());

            pageUtils.setList(ecsVoList);
        }

        return pageUtils;
    }

    /**
     * 查询ECS类型的所有指标，并标识是否已经被监视
     * @param params
     * @return
     */
    @Override
    public PageUtils queryMetricVoPageByType(Map<String, Object> params) {
        Integer type = Integer.parseInt((String) params.get("type"));
        Long hostId = Long.parseLong((String) params.get("hostId"));

        IPage<MetricEntity> page = metricService.page(
                new Query<MetricEntity>().getPage(params),
                new QueryWrapper<MetricEntity>().eq("type", type)
        );
        PageUtils pageUtils = new PageUtils(page);
        List<MetricEntity> metricEntities = page.getRecords();
        if(metricEntities.size()>0){
            List<MetricVo> metricVoList = metricEntities.stream().map(metric -> {
                MetricVo metricVo = new MetricVo();
                BeanUtils.copyProperties(metric, metricVo);
                EcsMetricRelationEntity one = ecsMetricRelationService.getOne(new QueryWrapper<EcsMetricRelationEntity>().eq("host_id", hostId).eq("metric_id", metric.getId()));

                metricVo.setIsMonitored(one==null?false:true);
                return metricVo;
            }).collect(Collectors.toList());
            pageUtils.setList(metricVoList);
        }

        return pageUtils;
    }

    /**
     * 给ECS添加监控指标
     * @param hostId ECS id
     * @param metricIds 要添加的所有指标id
     */
    @Override
    public void addMetrics(Long hostId, List<Long> metricIds) {
        List<EcsMetricRelationEntity> ecsMetricRelationEntities = metricIds.stream().map(id -> {
            EcsMetricRelationEntity relationEntity = new EcsMetricRelationEntity();
            relationEntity.setHostId(hostId);
            relationEntity.setMetricId(id);
            return relationEntity;
        }).collect(Collectors.toList());

        ecsMetricRelationService.saveBatch(ecsMetricRelationEntities);
    }

    /**
     * 取消ECS的指标监控
     * @param hostId ECS id
     * @param metricIds 要取消的指标id
     */
    @Transactional
    @Override
    public void cancelMetrics(Long hostId, List<Long> metricIds) {
        metricIds.stream().forEach(id->{
            ecsMetricRelationService.remove(new QueryWrapper<EcsMetricRelationEntity>().eq("host_id",hostId).eq("metric_id",id));
        });
    }

    /**
     * 根据用户id获取所属的ECS实例
     * @param userId
     * @return
     */
    @Override
    public List<EcsEntity> getEcsListByUserId(Long userId) {
        return this.baseMapper.getEcsListByUserId(userId);
    }

    @Override
    public EcsEntity getEcsByInstanceId(String instanceId) {
        return this.baseMapper.getEcsByInstanceId(instanceId);
    }

    /**
     * 删除ECS实例，同时删除模拟Mock的定时任务
     * @param ids
     */
    @Transactional
    @Override
    public void removeEcsByIds(List<Long> ids) {
        this.removeByIds(ids);
        ids.stream().forEach(id->{
            List<EcsMetricRelationEntity> relationEntities = ecsMetricRelationService.list(new QueryWrapper<EcsMetricRelationEntity>().eq("host_id", id));
            // 1.删除监控的指标
            ecsMetricRelationService.removeByIds(relationEntities.stream().map(item->{
                return item.getId();
            }).collect(Collectors.toList()));

            // 2.如果有告警规则，则删除所有告警规则
            List<RuleEcsRelationEntity> ruleEcsRelationEntities = ruleEcsRelationService.list(new QueryWrapper<RuleEcsRelationEntity>().eq("host_id", id));
            if(ruleEcsRelationEntities.size()>0){
                ruleEcsRelationEntities.forEach(relationEntity->{
                    // 2.1 删除关系
                    ruleEcsRelationService.removeById(relationEntity.getId());
                    // 2.2 删除rule
                    ruleService.removeById(relationEntity.getRuleId());
                    // rule描述和告警历史直接级联删除了
                });
                // 删除告警规则下的所有定时告警任务
                ruleService.deleteAlertTask(ruleEcsRelationEntities.stream().map(item->{
                    return item.getRuleId();
                }).collect(Collectors.toList()));
            }
        });
        // 删除模拟Mock定时任务
        deleteEcsMockTask(ids);
    }

    @Override
    public void deleteEcsMockTask(List<Long> ids) {
        // 删除EcsMockTask以及关系表
        for (Long id :
                ids) {
            List<JobEcsRelationEntity> relationEntities = jobEcsRelationService.list(new QueryWrapper<JobEcsRelationEntity>().eq("host_id", id));
            jobEcsRelationService.removeByIds(relationEntities.stream().map(item->{
                return item.getId();
            }).collect(Collectors.toList()));

            List<Long> jobIdList = relationEntities.stream().map(item -> {
                return item.getJobId();
            }).collect(Collectors.toList());
            Long[] jobIds = jobIdList.toArray(new Long[0]);
            // 只有这个方法能删除定时任务
            scheduleJobService.deleteBatch(jobIds);
        }
    }


    /**
     * 根据告警规则id获取ecs实例
     * @param ruleId
     * @return
     */
    @Override
    public EcsEntity getEcsByRuleId(Long ruleId) {

        return this.baseMapper.getEcsByRuleId(ruleId);
    }

    /**
     * 保存ecs实例后，开启Mock模拟任务
     * @param ecs
     */
    @Transactional
    @Override
    public void saveEcs(EcsEntity ecs) {
        this.save(ecs);

        // 保存ECS实例后，开启模拟Mock
        startEcsMockTask(ecs);
    }

    @Transactional
    @Override
    public void updateByRds(EcsEntity ecs) {
        this.updateById(ecs);
        
        //更新定时任务状态
        updateEcsMockTask(ecs);
    }

    /**
     * 更新模拟Mock任务状态
     * @param ecs
     */
    private void updateEcsMockTask(EcsEntity ecs) {
        JobEcsRelationEntity jobRdsRelationEntity = jobEcsRelationService.getOne(new QueryWrapper<JobEcsRelationEntity>().eq("host_id", ecs.getId()));
        ScheduleJobEntity scheduleJobEntity = scheduleJobService.getById(jobRdsRelationEntity.getJobId());
        if (ecs.getStatus() == Constant.RunningStatus.RUNNING.getValue()) {
            scheduleJobEntity.setStatus(Constant.ScheduleStatus.NORMAL.getValue());
        } else {
            scheduleJobEntity.setStatus(Constant.ScheduleStatus.PAUSE.getValue());
        }
        scheduleJobService.update(scheduleJobEntity);
    }

    /**
     * 开启模拟Mock
     * @param ecs
     */
    private void startEcsMockTask(EcsEntity ecs) {
        ScheduleJobEntity scheduleJobEntity = new ScheduleJobEntity();
        scheduleJobEntity.setStatus(ecs.getStatus()==Constant.RunningStatus.RUNNING.getValue()?Constant.ScheduleStatus.NORMAL.getValue():Constant.ScheduleStatus.PAUSE.getValue());
        scheduleJobEntity.setBeanName("ecsMockTask");
        scheduleJobEntity.setCronExpression("0/15 * * * * ? ");

        JSONObject paramsJson = new JSONObject();
        paramsJson.put("instanceId",ecs.getEcsId());
        scheduleJobEntity.setParams(paramsJson.toJSONString());

        scheduleJobService.saveJob(scheduleJobEntity);

        // 保存job和ecs的关系
        JobEcsRelationEntity jobEcsRelationEntity = new JobEcsRelationEntity();
        jobEcsRelationEntity.setHostId(ecs.getId());
        jobEcsRelationEntity.setJobId(scheduleJobEntity.getJobId());
        jobEcsRelationService.save(jobEcsRelationEntity);
    }

}